#include "stdafx.h"

namespace Event
{
    EventManager* EventManager::m_Singleton = NULL;

    EventManager::EventManager() :
        m_listMutex(),
        m_mapSignals(),
        m_mapSenderSignals(),
        m_mapListeners(),
        m_listEvents()
    {
    }

    EventManager::~EventManager()
    {
        destroyAllConnections();

        /*for (td_listEvents::iterator it_event = m_listEvents.begin();
			it_event != m_listEvents.end();
			++it_event)
		{
			td_mapSignals::iterator it_signal = m_mapSignals.find((*it_event)->getType());
			// we have to dereference 2 times the iterator to have the signal (not the pointer)
			// and we have to dereference the iterator of the event to have the event
			(*(it_signal->second))((*it_event));
		}*/
		m_listEvents.clear();

	    
		for (td_mapSignals::iterator it_signal = m_mapSignals.begin();
			it_signal != m_mapSignals.end();
			++it_signal)
		{
			if (it_signal->second != NULL)
				delete it_signal->second;
			it_signal->second = NULL;
		}
		m_mapSignals.clear();

        for (td_mapSenderSignals::iterator it_senderSignal = m_mapSenderSignals.begin();
			it_senderSignal != m_mapSenderSignals.end();
			++it_senderSignal)
		{
            if (it_senderSignal->second != NULL)
                delete it_senderSignal->second;
            it_senderSignal->second = NULL;
        }
		m_mapSenderSignals.clear();

		m_mapListeners.clear();
    }

	

    void EventManager::update(float _timeDelta)
    {
        m_listMutex.lock();

        // we have to sort the list
        m_listEvents.sort(EventManager::compareEvents);

        boost::shared_ptr< EventBase >	currentEvent;
		for (td_listEvents::iterator it_event = m_listEvents.begin();
             it_event != m_listEvents.end();
             ++it_event)
		{
			currentEvent = *it_event;
            // we update the event
            currentEvent->update(_timeDelta);
		}
		
		bool							goOn			= false;
        td_listEvents::iterator			it_event		= m_listEvents.begin();

        m_listMutex.unlock();

		if( it_event != m_listEvents.end() )
		{
            m_listMutex.lock();
			currentEvent = *it_event;
            m_listMutex.unlock();
			goOn = true;
		}
		else
			goOn = false;

		if( goOn )
		{
			if ( currentEvent->getRemainingTime() < 0.0f )
			{
				goOn = true;
			}
			else
			{
				goOn = false;
			}
		}
		else
			goOn = false;

        while ( goOn )
        {
            td_mapSignals::iterator it_signal = m_mapSignals.find( currentEvent->getType());
            std::pair< unsigned int, void* > eventSender = std::make_pair( currentEvent->getType(), currentEvent->getSender());
            td_mapSenderSignals::iterator it_senderSignal = m_mapSenderSignals.find(eventSender);

            if (it_signal != m_mapSignals.end())
            {
                // we have to dereference 2 times the iterator to have the signal (not the pointer)
                // and we have to dereference the iterator of the event to have the event
                (*(it_signal->second))( currentEvent );
            }

            if (it_senderSignal != m_mapSenderSignals.end())
            {
                // we have to dereference 2 times the iterator to have the signal (not the pointer)
                // and we have to dereference the iterator of the event to have the event
                (*(it_senderSignal->second))( currentEvent );
            }

			currentEvent->fired();
            m_listMutex.lock();
			it_event++;          
            m_listMutex.unlock();

			if( it_event != m_listEvents.end() )
			{
                m_listMutex.lock();
				currentEvent = *it_event;
                m_listMutex.unlock();
				goOn = true;
			}
			else
				goOn = false;

			if( goOn )
			{
				if ( currentEvent->getRemainingTime() < 0.0f )
				{
					goOn = true;
				}
				else
				{
					goOn = false;
				}
			}
			else
			{
				goOn = false;
			}
        }

        m_listMutex.lock();
		m_listEvents.remove_if( EventBase::_RemoveByTime_() );
        m_listMutex.unlock();
    }

    void EventManager::connect(void* _listener, enum_typeEvent _eventID, const td_eventBaseSignal::slot_type &_subscriber)
    {
        // if the _eventID is a known ID we try to find the corresponding signal
        if (_eventID >= 0 && _eventID < MAX_EVENT_TYPE)
        {
            td_mapSignals::iterator it_signal = m_mapSignals.find(_eventID);

            // If we don't fine the signal, we have to create it
            if (it_signal == m_mapSignals.end())
            {
                it_signal = m_mapSignals.insert(td_mapSignals::value_type(_eventID, new td_eventBaseSignal)).first;
            }

            //we connect and create the blocker
            boost::signals2::shared_connection_block blocker(it_signal->second->connect(_subscriber), false);

            // we have to create the map of listeners if it doesn't exist
            td_mapListeners::iterator it_listener = m_mapListeners.find(_listener);
            if (it_listener == m_mapListeners.end())
            {
                m_mapListeners[_listener].insert(
                                                 td_mapConnectionBlock::value_type(
                                                                                   _eventID,
                                                                                   blocker
                                                                                   )
                                                 );
            }
            else
            {
                it_listener->second.insert(
                                           td_mapConnectionBlock::value_type(
                                                                             _eventID,
                                                                             blocker
                                                                             )
                                           );
            }
        }
    }

    void EventManager::connect(void* _listener, enum_typeEvent _eventID, void * _sender, const td_eventBaseSignal::slot_type &_subscriber)
    {
        // if the _eventID is a known ID we try to find the corresponding signal
        if (_eventID >= 0 && _eventID < MAX_EVENT_TYPE)
        {
            std::pair< unsigned int, void* > eventSender = std::make_pair(_eventID, _sender);
            td_mapSenderSignals::iterator it_signal = m_mapSenderSignals.find(eventSender);

            // If we don't fine the signal, we have to create it
            if (it_signal == m_mapSenderSignals.end())
            {
                it_signal = m_mapSenderSignals.insert(td_mapSenderSignals::value_type(eventSender, new td_eventBaseSignal)).first;
            }

            //we connect and create the blocker
            boost::signals2::shared_connection_block blocker(it_signal->second->connect(_subscriber), false);

            // we have to create the map of listeners if it doesn't exist
            td_mapListeners::iterator it_listener = m_mapListeners.find(_listener);
            if (it_listener == m_mapListeners.end())
            {
                m_mapListeners[_listener].insert(
                                                 td_mapConnectionBlock::value_type(
                                                                                   _eventID,
                                                                                   blocker
                                                                                   )
                                                 );
            }
            else
            {
                it_listener->second.insert(
                                           td_mapConnectionBlock::value_type(
                                                                             _eventID,
                                                                             blocker
                                                                             )
                                           );
            }
        }
    }

    void EventManager::postEvent(boost::shared_ptr<EventBase> _event)
    {
        static clock_t timeToWait = 0;

        clock_t time = clock();
        if ( _event->getType() == EVENT_CHANGE_POSITION || _event->getType() == EVENT_NEED_GENERIK_SCENT_ADD )
        {
            if ( time - timeToWait < 10 )
            {
                return;
            }
        }
		std::cout << _event->getType() << std::endl;
        timeToWait = time;

        if ( _event->getSender() )
        {
            // we check if the signal is created, if not we create it
            std::pair< unsigned int, void* > eventSender = std::make_pair(_event->getType(), _event->getSender());
            td_mapSenderSignals::iterator it_signal = m_mapSenderSignals.find(eventSender);

            if (it_signal == m_mapSenderSignals.end())
            {
                it_signal = m_mapSenderSignals.insert(td_mapSenderSignals::value_type(eventSender, new td_eventBaseSignal)).first;
            }
        }
        else
        {
            // we check if the signal is created, if not we create it
            td_mapSignals::iterator it_signal = m_mapSignals.find(_event->getType());

            if (it_signal == m_mapSignals.end())
            {
                it_signal = m_mapSignals.insert(td_mapSignals::value_type(_event->getType(), new td_eventBaseSignal)).first;
            }
        }

        // we add the event if the remaining time is greater than 0
        /*
        if (_event->getRemainingTime() <= 0.0f)
        {
            // we have to dereference 2 times the iterator to have the signal (not the pointer)
            // and we have to dereference the iterator of the event to have the event
            (*(it_signal->second))(_event);

            if (_event->fired() > 0)
            {
                // we add the event
                m_listEvents.push_back(_event);

                // we have to sort the list
                m_listEvents.sort(EventManager::compareEvents);
            }
        }
        else*/
        {
            m_listMutex.lock();
            m_listEvents.push_back(_event);
            m_listMutex.unlock();

			/*try
			{
				// we have to sort the list
				m_listEvents.sort(EventManager::compareEvents);

			}catch( ... )
			{
				
#if defined(_DEBUG) && defined(_OUTPUT)
				std::cout << "EventManager => Erreur de shared_ptr dans std::list<>::sort" << std::endl;
#endif
			}*/
        }
    }

    bool EventManager::compareEvents(boost::shared_ptr<EventBase> _first, boost::shared_ptr<EventBase> _second)
    {
		if( _first.get() == NULL )
			return false;
		if( _second.get() == NULL )
			return true;
		if( _first == _second )
			return false;

        return ( *(_first.get()) < *(_second.get()) );
    }

} //  namespace Event
